﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TrackerRealm.Jazz.Client;
using TrackerRealm.Jazz.Common;
using TrackerRealm.Jazz.Client.Custom;

namespace ConsoleDemo
{
    public class JazzConsole
    {
        public static bool DispalyJazzObject(jObject jazzObject)
        {
            // get the properties and methods that should be displayed.
            jMemberInfo[] members = jazzObject.GetWrappedMembers().UI().ToArray();

            Console.ForegroundColor = ConsoleColor.White;
            do
            {
                // get the name and the value of the properties
                string[] propValueMembers = members.Where(m => m.CanRead).Select<jMemberInfo, string>(m => m.Name + "='" + m.Read(jazzObject) + "'").ToArray();

                Console.WriteLine("Data = " + string.Join(", ", propValueMembers));
            }
            while (ProcessCommands(GetCommands(jazzObject), jazzObject));
            return false;
            
        }
        public static Dictionary<string, jMemberInfo> GetCommands(jObject jazzObj)
        {
            Dictionary<string, jMemberInfo> dict = new Dictionary<string, jMemberInfo>();
            // get the members we care about (marked with 'UI' attribute)
            jMemberInfo[] members = jazzObj.GetWrappedMembers().UI().Where(m => m.IsMethod || m.IsProperty && !m.WriteAccessor.IsEmpty).ToArray();
            foreach (jMemberInfo member in members)
            {
                string command = member.Name.Substring(0, 1).ToLower();
                if (dict.ContainsKey(command))
                {
                    int i = 2;
                    do
                    {
                        jMemberInfo m = dict[command];
                        dict.Remove(command);
                        dict.Add(m.Name.Substring(0, i).ToLower(), m);
                        command = member.Name.Substring(0, i).ToLower();
                        i++;
                    } while (dict.ContainsKey(command));
                }
                dict.Add(command, member);
            }
            return dict;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="cmdDict"></param>
        /// <param name="jazzObj"></param>
        /// <returns></returns>
        public static bool ProcessCommands(Dictionary<string, jMemberInfo> cmdDict, jObject jazzObj)
        {
            ClientNexus nexus = (ClientNexus)jazzObj.ClientNexus;
            Console.ForegroundColor = ConsoleColor.White;
            Console.Write("Current State: '");
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.Write(jazzObj.CurrentState.Name);
            Console.ForegroundColor = ConsoleColor.White;
            Console.Write("  Login Roles: ");
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.Write(string.Format("'{0}'",String.Join("' ,'", nexus.LoginRoles.Select<jRole, string>(r => r.Name).ToArray())));
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine( "");
            string cmd;
            do
            {
                cmd = "";
                string availCmds;
                // get all the executable methods (commands) and properties that are allowed to be set. - Mark them 'GREEN'
                availCmds = string.Join(", ", cmdDict.Where(c => c.Value.CanWrite || c.Value.IsExecutable).Select<KeyValuePair<string, jMemberInfo>, string>(kvp => kvp.Key + "--" + kvp.Value.Name).ToArray());
                Console.Write("Available Commands = " );
                Console.ForegroundColor = ConsoleColor.Green;
                Console.Write( availCmds);
                // get all the methods and properties that are not allow to be exected or set. - Mark them 'RED'
                string redCmds = string.Join(", ", cmdDict.Where(c => (c.Value.IsGrey) || (c.Value.WriteAccessor.IsGrey)).Select<KeyValuePair<string, jMemberInfo>, string>(kvp => kvp.Key + "--" + kvp.Value.Name).ToArray());
               
                if (availCmds != "") redCmds = ", " + redCmds;
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine( redCmds);
                Console.ForegroundColor = ConsoleColor.White;
                string[] cmds = cmdDict.Select<KeyValuePair<string, jMemberInfo>, string>(kvp => kvp.Key).ToArray();
                Console.Write("Enter Command:>");
                do
                {
                    ConsoleKeyInfo keyInfo = Console.ReadKey();
                    cmd += keyInfo.KeyChar.ToString();
                }
                while (cmds.FirstOrDefault(c => c.StartsWith(cmd)) != null  && cmds.FirstOrDefault(c => c == cmd) == null );

                if ((int)cmd[0] == 27 || cmd[0] == '\r')
                {
                    Console.WriteLine();
                    return false;
                }
            } while (!cmdDict.ContainsKey(cmd));
            Console.WriteLine();
            jMemberInfo m = cmdDict[cmd];
            if (m.IsProperty)
            {
                Console.Write("Enter Data:>");
                string value = Console.ReadLine();
                try
                {
                    Type t = m.PropertyInfo.PropertyType;
                    object writeValue = Convert.ChangeType(value, t);
                    Console.ForegroundColor = ConsoleColor.Gray;
                    m.Write(jazzObj, writeValue);
                    Console.ForegroundColor = ConsoleColor.White;
                }
                catch (Exception ex)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("AccessViolationException: " + ex.Message);
                    if (ex.InnerException != null)
                        Console.WriteLine(ex.InnerException.Message);
                    Console.ForegroundColor = ConsoleColor.White;
                }
            }
            else if (m.IsMethod)
            {
                if (m.MethodInfo.GetParameters().Count() == 0)
                    try
                    {
                        Console.ForegroundColor = ConsoleColor.Gray;
                        m.Execute(jazzObj);
                        Console.ForegroundColor = ConsoleColor.White;
                    }
                    catch (Exception ex)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("AccessViolationException: " + ex.Message);
                        if(ex.InnerException != null)
                            Console.WriteLine(ex.InnerException.Message);
                        Console.ForegroundColor = ConsoleColor.White;
                    }
                else
                    throw new ApplicationException("Can not handle methods with parameters.");
            }
            else throw new InvalidOperationException("Not expected.  Bug in program.");
            return true;
        }

        public static bool GetLoginUser(ClientNexus nexus, out jUser loginUser)
        {
            string user;
            do
            {
                loginUser = nexus.Cache.NamedObjects.Get<jUser>("Empty");
                jUser[] users = nexus.Cache.Where(j => j is jUser).Cast<jUser>().ToArray();
                Console.Write("Users = ");
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine(string.Format("'{0}'", string.Join("', '", users.Select<jUser, string>(u => u.Name).ToArray())));
                Console.ForegroundColor = ConsoleColor.White;
                
                Console.Write("Enter Login User:>");
                if(!ReadCommand(users.Select<jUser,string>(u => u.Name).ToArray(), out user))
                {
                    return false;
                }
            }
            while (!nexus.Cache.NamedObjects.TryGetSingleUnit<jUser>(user, out loginUser));
            return true;
        }
        public static bool ReadCommand(string[] cmds, out string cmd)
        {
            cmd = "";
            //char keyChar;
            //string command = "";
            //do
            //{
            //    ConsoleKeyInfo key = Console.ReadKey();
            //    keyChar = key.KeyChar;
            //    command += keyChar.ToString();

            //    if (cmds.FirstOrDefault(c => c == command) != null)
            //    {
            //        cmd = command;
            //        Console.WriteLine();
            //        return true;
            //    }
            //} while ((int)keyChar != 27 && keyChar != '\n');
            string line;
            line = Console.ReadLine();
            if (line == "") return false;
            cmd = line;
            return true;
        }
    }
}
